package cn.bingoo.handy;

import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.UUID;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;

import cn.bingoo.swing.utils.Clipboards;
import cn.bingoo.swing.utils.Swings;

import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;

public class RandomFrame extends JFrame {
    private static final long serialVersionUID = -467492574672386810L;
    private JPanel contentPane;
    private JTextField txtSeeds;
    private JTextField txtFilter;
    final JTextArea textResult;
    private JTextField textLength;
    private JTextField textTimes;

    /**
     * Launch the application.
     * @throws Exception 
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    RandomFrame frame = new RandomFrame();
                    frame.setVisible(true);
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public RandomFrame() {
        setTitle("Random Generator");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 817, 459);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        GridBagLayout gbl_contentPane = new GridBagLayout();
        gbl_contentPane.columnWidths = new int[] { 0, 0 };
        gbl_contentPane.rowHeights = new int[] { 0, 0, 0, 0, 0 };
        gbl_contentPane.columnWeights = new double[] { 1.0, Double.MIN_VALUE };
        gbl_contentPane.rowWeights = new double[] { 0.0, 0.0, 1.0, 0.0, Double.MIN_VALUE };
        contentPane.setLayout(gbl_contentPane);

        JPanel panel_4 = new JPanel();
        GridBagConstraints gbc_panel_4 = new GridBagConstraints();
        gbc_panel_4.insets = new Insets(0, 0, 5, 0);
        gbc_panel_4.fill = GridBagConstraints.BOTH;
        gbc_panel_4.gridx = 0;
        gbc_panel_4.gridy = 0;
        contentPane.add(panel_4, gbc_panel_4);
        GridBagLayout gbl_panel_4 = new GridBagLayout();
        gbl_panel_4.columnWidths = new int[] { 0, 0, 0, 0, 0 };
        gbl_panel_4.rowHeights = new int[] { 0, 0 };
        gbl_panel_4.columnWeights = new double[] { 0.0, 1.0, 0.0, 0.0, Double.MIN_VALUE };
        gbl_panel_4.rowWeights = new double[] { 0.0, Double.MIN_VALUE };
        panel_4.setLayout(gbl_panel_4);

        JLabel lblSeeds = new JLabel("Seeds:");
        GridBagConstraints gbc_lblSeeds = new GridBagConstraints();
        gbc_lblSeeds.anchor = GridBagConstraints.WEST;
        gbc_lblSeeds.insets = new Insets(0, 0, 0, 5);
        gbc_lblSeeds.gridx = 0;
        gbc_lblSeeds.gridy = 0;
        panel_4.add(lblSeeds, gbc_lblSeeds);

        txtSeeds = new JTextField();
        txtSeeds.setText("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 _.!@#$%^&*");
        GridBagConstraints gbc_txtSeeds = new GridBagConstraints();
        gbc_txtSeeds.fill = GridBagConstraints.HORIZONTAL;
        gbc_txtSeeds.gridwidth = 2;
        gbc_txtSeeds.insets = new Insets(0, 0, 0, 5);
        gbc_txtSeeds.gridx = 1;
        gbc_txtSeeds.gridy = 0;
        panel_4.add(txtSeeds, gbc_txtSeeds);
        txtSeeds.setColumns(10);

        final JCheckBox chckbxChinese = new JCheckBox("一级汉字");
        GridBagConstraints gbc_chckbxChinese = new GridBagConstraints();
        gbc_chckbxChinese.anchor = GridBagConstraints.WEST;
        gbc_chckbxChinese.gridx = 3;
        gbc_chckbxChinese.gridy = 0;
        panel_4.add(chckbxChinese, gbc_chckbxChinese);

        JPanel panel_3 = new JPanel();
        GridBagConstraints gbc_panel_3 = new GridBagConstraints();
        gbc_panel_3.insets = new Insets(0, 0, 5, 0);
        gbc_panel_3.fill = GridBagConstraints.BOTH;
        gbc_panel_3.gridx = 0;
        gbc_panel_3.gridy = 1;
        contentPane.add(panel_3, gbc_panel_3);
        GridBagLayout gbl_panel_3 = new GridBagLayout();
        gbl_panel_3.columnWidths = new int[] { 0, 34, 0, 0, 0, 0, 0, 0 };
        gbl_panel_3.rowHeights = new int[] { 0, 0 };
        gbl_panel_3.columnWeights = new double[] { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE };
        gbl_panel_3.rowWeights = new double[] { 0.0, Double.MIN_VALUE };
        panel_3.setLayout(gbl_panel_3);

        JLabel lblMaxLen = new JLabel("Len:");
        GridBagConstraints gbc_lblMaxLen = new GridBagConstraints();
        gbc_lblMaxLen.anchor = GridBagConstraints.EAST;
        gbc_lblMaxLen.insets = new Insets(0, 0, 0, 5);
        gbc_lblMaxLen.gridx = 0;
        gbc_lblMaxLen.gridy = 0;
        panel_3.add(lblMaxLen, gbc_lblMaxLen);

        textLength = new JTextField();
        textLength.setText("16");
        GridBagConstraints gbc_textLength = new GridBagConstraints();
        gbc_textLength.anchor = GridBagConstraints.WEST;
        gbc_textLength.insets = new Insets(0, 0, 0, 5);
        gbc_textLength.gridx = 1;
        gbc_textLength.gridy = 0;
        panel_3.add(textLength, gbc_textLength);
        textLength.setColumns(10);

        JLabel lblTimes = new JLabel("Times:");
        GridBagConstraints gbc_lblTimes = new GridBagConstraints();
        gbc_lblTimes.anchor = GridBagConstraints.EAST;
        gbc_lblTimes.insets = new Insets(0, 0, 0, 5);
        gbc_lblTimes.gridx = 2;
        gbc_lblTimes.gridy = 0;
        panel_3.add(lblTimes, gbc_lblTimes);

        textTimes = new JTextField();
        textTimes.setText("10");
        GridBagConstraints gbc_textTimes = new GridBagConstraints();
        gbc_textTimes.insets = new Insets(0, 0, 0, 5);
        gbc_textTimes.fill = GridBagConstraints.HORIZONTAL;
        gbc_textTimes.gridx = 3;
        gbc_textTimes.gridy = 0;
        panel_3.add(textTimes, gbc_textTimes);
        textTimes.setColumns(10);

        final JButton btnGenerate = new JButton("Generate");
        GridBagConstraints gbc_btnGenerate = new GridBagConstraints();
        gbc_btnGenerate.fill = GridBagConstraints.HORIZONTAL;
        gbc_btnGenerate.insets = new Insets(0, 0, 0, 5);
        gbc_btnGenerate.gridx = 4;
        gbc_btnGenerate.gridy = 0;
        panel_3.add(btnGenerate, gbc_btnGenerate);

        JButton btnUuid = new JButton("UUID");
        GridBagConstraints gbc_btnUuid = new GridBagConstraints();
        gbc_btnUuid.insets = new Insets(0, 0, 0, 5);
        gbc_btnUuid.fill = GridBagConstraints.HORIZONTAL;
        gbc_btnUuid.gridx = 5;
        gbc_btnUuid.gridy = 0;
        panel_3.add(btnUuid, gbc_btnUuid);

        JButton btnClear = new JButton("Clear");
        btnClear.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Swings.clearText(textResult);
            }
        });
        GridBagConstraints gbc_btnClear = new GridBagConstraints();
        gbc_btnClear.gridx = 6;
        gbc_btnClear.gridy = 0;
        panel_3.add(btnClear, gbc_btnClear);

        JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
        GridBagConstraints gbc_tabbedPane = new GridBagConstraints();
        gbc_tabbedPane.insets = new Insets(0, 0, 5, 0);
        gbc_tabbedPane.fill = GridBagConstraints.BOTH;
        gbc_tabbedPane.gridx = 0;
        gbc_tabbedPane.gridy = 2;
        contentPane.add(tabbedPane, gbc_tabbedPane);

        JScrollPane scrollPane = new JScrollPane();
        tabbedPane.addTab("Random Result", null, scrollPane, null);

        textResult = new JTextArea();
        textResult.setLineWrap(true);
        textResult.setFont(new Font("微软雅黑", Font.PLAIN, 13));
        scrollPane.setViewportView(textResult);

        JScrollPane panel_2 = new JScrollPane();
        tabbedPane.addTab("ASCII", null, panel_2, null);

        JTextArea txtrCharDecOct = new JTextArea();
        txtrCharDecOct.setEditable(false);
        txtrCharDecOct.setFont(new Font("Consolas", Font.PLAIN, 13));
        txtrCharDecOct
                .setText("Char  Dec  Oct  Hex | Char  Dec  Oct  Hex | Char  Dec  Oct  Hex | Char Dec  Oct   Hex\r\n-------------------------------------------------------------------------------------\r\n(nul)   0 0000 0x00 | (sp)   32 0040 0x20 | @      64 0100 0x40 | `      96 0140 0x60\r\n(soh)   1 0001 0x01 | !      33 0041 0x21 | A      65 0101 0x41 | a      97 0141 0x61\r\n(stx)   2 0002 0x02 | \"      34 0042 0x22 | B      66 0102 0x42 | b      98 0142 0x62\r\n(etx)   3 0003 0x03 | #      35 0043 0x23 | C      67 0103 0x43 | c      99 0143 0x63\r\n(eot)   4 0004 0x04 | $      36 0044 0x24 | D      68 0104 0x44 | d     100 0144 0x64\r\n(enq)   5 0005 0x05 | %      37 0045 0x25 | E      69 0105 0x45 | e     101 0145 0x65\r\n(ack)   6 0006 0x06 | &      38 0046 0x26 | F      70 0106 0x46 | f     102 0146 0x66\r\n(bel)   7 0007 0x07 | '      39 0047 0x27 | G      71 0107 0x47 | g     103 0147 0x67\r\n(bs)    8 0010 0x08 | (      40 0050 0x28 | H      72 0110 0x48 | h     104 0150 0x68\r\n(ht)    9 0011 0x09 | )      41 0051 0x29 | I      73 0111 0x49 | i     105 0151 0x69\r\n(nl)   10 0012 0x0a | *      42 0052 0x2a | J      74 0112 0x4a | j     106 0152 0x6a\r\n(vt)   11 0013 0x0b | +      43 0053 0x2b | K      75 0113 0x4b | k     107 0153 0x6b\r\n(np)   12 0014 0x0c | ,      44 0054 0x2c | L      76 0114 0x4c | l     108 0154 0x6c\r\n(cr)   13 0015 0x0d | -      45 0055 0x2d | M      77 0115 0x4d | m     109 0155 0x6d\r\n(so)   14 0016 0x0e | .      46 0056 0x2e | N      78 0116 0x4e | n     110 0156 0x6e\r\n(si)   15 0017 0x0f | /      47 0057 0x2f | O      79 0117 0x4f | o     111 0157 0x6f\r\n(dle)  16 0020 0x10 | 0      48 0060 0x30 | P      80 0120 0x50 | p     112 0160 0x70\r\n(dc1)  17 0021 0x11 | 1      49 0061 0x31 | Q      81 0121 0x51 | q     113 0161 0x71\r\n(dc2)  18 0022 0x12 | 2      50 0062 0x32 | R      82 0122 0x52 | r     114 0162 0x72\r\n(dc3)  19 0023 0x13 | 3      51 0063 0x33 | S      83 0123 0x53 | s     115 0163 0x73\r\n(dc4)  20 0024 0x14 | 4      52 0064 0x34 | T      84 0124 0x54 | t     116 0164 0x74\r\n(nak)  21 0025 0x15 | 5      53 0065 0x35 | U      85 0125 0x55 | u     117 0165 0x75\r\n(syn)  22 0026 0x16 | 6      54 0066 0x36 | V      86 0126 0x56 | v     118 0166 0x76\r\n(etb)  23 0027 0x17 | 7      55 0067 0x37 | W      87 0127 0x57 | w     119 0167 0x77\r\n(can)  24 0030 0x18 | 8      56 0070 0x38 | X      88 0130 0x58 | x     120 0170 0x78\r\n(em)   25 0031 0x19 | 9      57 0071 0x39 | Y      89 0131 0x59 | y     121 0171 0x79\r\n(sub)  26 0032 0x1a | :      58 0072 0x3a | Z      90 0132 0x5a | z     122 0172 0x7a\r\n(esc)  27 0033 0x1b | ;      59 0073 0x3b | [      91 0133 0x5b | {     123 0173 0x7b\r\n(fs)   28 0034 0x1c | <      60 0074 0x3c | \\      92 0134 0x5c | |     124 0174 0x7c\r\n(gs)   29 0035 0x1d | =      61 0075 0x3d | ]      93 0135 0x5d | }     125 0175 0x7d\r\n(rs)   30 0036 0x1e | >      62 0076 0x3e | ^      94 0136 0x5e | ~     126 0176 0x7e\r\n(us)   31 0037 0x1f | ?      63 0077 0x3f | _      95 0137 0x5f | (del) 127 0177 0x7f");
        panel_2.setViewportView(txtrCharDecOct);

        JPanel panel_1 = new JPanel();
        GridBagConstraints gbc_panel_1 = new GridBagConstraints();
        gbc_panel_1.fill = GridBagConstraints.BOTH;
        gbc_panel_1.gridx = 0;
        gbc_panel_1.gridy = 3;
        contentPane.add(panel_1, gbc_panel_1);
        GridBagLayout gbl_panel_1 = new GridBagLayout();
        gbl_panel_1.columnWidths = new int[] { 0, 0, 0, 0, 0, 0 };
        gbl_panel_1.rowHeights = new int[] { 0, 0 };
        gbl_panel_1.columnWeights = new double[] { 0.0, 0.0, 0.0, 0.0, 1.0, Double.MIN_VALUE };
        gbl_panel_1.rowWeights = new double[] { 0.0, Double.MIN_VALUE };
        panel_1.setLayout(gbl_panel_1);

        JButton btnCopy = new JButton("Copy");
        btnCopy.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Clipboards.setClipboard(textResult.getText());
            }
        });
        GridBagConstraints gbc_btnCopy = new GridBagConstraints();
        gbc_btnCopy.anchor = GridBagConstraints.EAST;
        gbc_btnCopy.insets = new Insets(0, 0, 0, 5);
        gbc_btnCopy.gridx = 0;
        gbc_btnCopy.gridy = 0;
        panel_1.add(btnCopy, gbc_btnCopy);

        JButton btnUppercase = new JButton("UpperCase");
        btnUppercase.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                textResult.setText(textResult.getText().toUpperCase());
            }
        });
        GridBagConstraints gbc_btnUppercase = new GridBagConstraints();
        gbc_btnUppercase.insets = new Insets(0, 0, 0, 5);
        gbc_btnUppercase.gridx = 1;
        gbc_btnUppercase.gridy = 0;
        panel_1.add(btnUppercase, gbc_btnUppercase);

        JButton btnLowercase = new JButton("LowerCase");
        btnLowercase.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                textResult.setText(textResult.getText().toLowerCase());
            }
        });
        GridBagConstraints gbc_btnLowercase = new GridBagConstraints();
        gbc_btnLowercase.insets = new Insets(0, 0, 0, 5);
        gbc_btnLowercase.gridx = 2;
        gbc_btnLowercase.gridy = 0;
        panel_1.add(btnLowercase, gbc_btnLowercase);

        JButton btnFilter = new JButton("Filter");
        btnFilter.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String filteredStr = new CharMatcher() {
                    String filterText = txtFilter.getText();

                    @Override
                    public boolean matches(char c) {
                        return filterText.indexOf(c) >= 0;
                    }
                }.removeFrom(textResult.getText());
                textResult.setText(filteredStr);
            }
        });
        GridBagConstraints gbc_btnFilter = new GridBagConstraints();
        gbc_btnFilter.insets = new Insets(0, 0, 0, 5);
        gbc_btnFilter.gridx = 3;
        gbc_btnFilter.gridy = 0;
        panel_1.add(btnFilter, gbc_btnFilter);

        txtFilter = new JTextField();
        GridBagConstraints gbc_txtFilter = new GridBagConstraints();
        gbc_txtFilter.fill = GridBagConstraints.HORIZONTAL;
        gbc_txtFilter.gridx = 4;
        gbc_txtFilter.gridy = 0;
        panel_1.add(txtFilter, gbc_txtFilter);
        txtFilter.setColumns(10);

        final RandomFrame randomFrame = this;
        btnGenerate.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int len = 0;
                try {
                    len = Integer.parseInt(textLength.getText().trim());
                }
                catch (Exception ex) {
                    JOptionPane.showMessageDialog(randomFrame, "Input Error in MaxLength Field!");
                    return;
                }
                int times = 0;
                try {
                    times = Integer.parseInt(textTimes.getText().trim());
                }
                catch (Exception ex) {
                    JOptionPane.showMessageDialog(randomFrame, "Input Error in MaxLength Field!");
                    return;
                }

                Iterable<String> seeds = Splitter.on(CharMatcher.WHITESPACE).omitEmptyStrings().trimResults()
                        .split(txtSeeds.getText());
                ArrayList<String> seedsArr = new ArrayList<String>();
                for (String seed : seeds) {
                    seedsArr.add(new SeedsStringParser().parse(seed));
                }

                if (chckbxChinese.isSelected()) {
                    seedsArr.add(ChineseUtils.levelOne());// new SeedsStringParser().parse("\\u4e00-\\u9fa5");
                }
                if (seedsArr.size() == 0) {
                    JOptionPane.showMessageDialog(randomFrame, "No seeds defined!");
                    return;
                }

                btnGenerate.setEnabled(false);
                new Thread(new RandomRun(len, times, btnGenerate, textResult,
                        seedsArr.toArray(new String[seedsArr.size()]))).start();
            }
        });
        btnUuid.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int times = 0;
                try {
                    times = Integer.parseInt(textTimes.getText().trim());
                }
                catch (Exception ex) {
                    JOptionPane.showMessageDialog(randomFrame, "Input Error in MaxLength Field!");
                    return;
                }
                for (int i = 0; i < times; ++i) {
                    if (i > 0 || textResult.getDocument().getLength() > 0) {
                        Swings.appendText(textResult, "\r\n", null);
                    }

                    String uuid = UUID.randomUUID().toString();
                    Swings.appendText(textResult, uuid, null);
                }
            }
        });
    }

    private static class RandomRun implements Runnable {
        private int len;
        private JButton btnGenerate;
        private JTextArea textResult;
        private String[] seeds;
        private int times;

        public RandomRun(int len, int times, JButton btnGenerate, JTextArea textResult, String[] seeds) {
            this.len = len;
            this.times = times;
            this.btnGenerate = btnGenerate;
            this.textResult = textResult;
            this.seeds = seeds;
        }

        @Override
        public void run() {
            btnGenerate.setEnabled(false);

            SecureRandom r = new SecureRandom();
            for (int i = 0; i < times; ++i) {
                if (i > 0 || textResult.getDocument().getLength() > 0) {
                    Swings.appendText(textResult, "\r\n", null);
                }
                StringBuilder pass = new StringBuilder(len);
                while (pass.length() < len) {
                    int rPick = r.nextInt(seeds.length);
                    String seed = seeds[rPick];
                    pass.append(seed.charAt(r.nextInt(seed.length())));
                }
                Swings.appendText(textResult, pass.toString(), null);
            }

            btnGenerate.setEnabled(true);
        }
    }
}
